#!/usr/bin/env python
# -*- coding: utf-8 -*-

# This application is released under the GNU General Public License 
# v2 (or, at your option, any later version). You can find the full 
# text of the license under http://www.gnu.org/licenses/gpl.txt. 
# By using, editing and/or distributing this software you agree to 
# the terms and conditions of this license. 
# Thank you for using free software!

#  TwitterScreenlet © papamitra 2008, boamaod 2010
#  Icon © Luc Latulippe 2009 (Creative Commons License)

# TODO
# - gtk.Entry() sizing

import screenlets
# from screenlets import utils
from screenlets.options import StringOption , BoolOption , IntOption , FileOption , DirectoryOption , ListOption , AccountOption , TimeOption , FontOption, ColorOption , ImageOption
from screenlets.options import create_option_from_node
from screenlets import DefaultMenuItem

import pango
import cairo
import pangocairo
import sys
import gtk
import gobject
import os
import urllib
import xml.sax.saxutils
import webbrowser

from ConfigParser import SafeConfigParser

from ThemeParser import ThemeParser

from TwitterBackend import TwitterBackend, TwitterUpdateMethod, Timeline, TwitterResult

import traceback

PI = 3.141596

# get from PidginScreenelt
def scaleGdkPixbuf(pixbuf,size):
    newpixbuf = None
    try:
        icw = pixbuf.get_width()
        ich = pixbuf.get_height()
        aspect = float(icw)/ich
        if aspect < 1: newpixbuf = pixbuf.scale_simple(int(aspect*size),size,1)
        elif aspect > 1: newpixbuf = pixbuf.scale_simple(size,int(size/aspect),1)
        else: newpixbuf = pixbuf.scale_simple(size,size,1)
    except:
        None
    return newpixbuf

def escape_for_pango_markup(string):
    # escapes < > & ' "
    # for pango markup not to break
    if string is None:
        return
    if gtk.pygtk_version >= (2, 8, 0) and gtk.gtk_version >= (2, 8, 0):
        escaped_str = gobject.markup_escape_text(string)
    else:
        escaped_str = xml.sax.saxutils.escape(string, {"'": '&apos;',
                                                       '"': '&quot;'})

    return escaped_str

X_SIZE = 210
Y_SIZE = 510

class TwitterScreenlet (screenlets.Screenlet):
    """Displays tweets of your friends or latest public tweets and lets you post your own."""

    # default meta-info for Screenlets (should be removed and put into metainfo)
    __name__	= 'TwitterScreenlet'
    __version__	= '0.9.1'
    __author__	= 'Guido Tabbernuk <boamaod@gmail.com>'
    __requires__ = ['python-twitter (>= 0.8)', 'python-oauth2']
    __desc__	= __doc__	# set description to docstring of class

    __timeout = None
    
    __fixed = None
    __entry = None

    __status_on_tooltip = None

    __twitter = None

    __notifier = None
    _TwitterBackend__notifier = None
    access_key = ""
    access_secret = ""
    access_pin = ''

    request_key = ""
    request_secret = ""


    item_font = "Sans Medium 10"
#    account = ["", ""]
    layout = None

    __timeline = Timeline()

    show_public_timeline = True
    num_of_statuses = 10
    update_interval = 320
    show_tooltips = True

    header_height = 26
    footer_height = 35
    user_icon_size = 30
    real_window_height = 500

    window_height = real_window_height - header_height - footer_height

    window_x = 10
    window_y = 10

    window_width = 200

    highlight = -1
    entry_highlighting = True

    #for scroll
    statuses_offset = 0
    _buffer = None
    scroll_width = 20

    public_title = "Public Tweets"
    friends_title = "Friends' Tweets"

    status_format = "<span foreground=\"%s\"><b>%s</b></span> <span foreground=\"%s\">%s</span>"
    entry_tooltip = "Use max 140 chars to make the point...\n<⇧ Shift> + <↵ Enter> to submit"
    status_tooltip = "Double click to open in browser,\nuse wheel to scroll up/down the list"

    initialized = False

    def __init__ (self, **keyword_args):
        screenlets.Screenlet.__init__(self, width=X_SIZE, height=Y_SIZE,
                                      uses_theme=True, **keyword_args)
        if not self.theme:
            self.theme_name="default"

        self.add_options_group('Appearance', 'Presentation of the tweets')

        self.add_option(BoolOption('Appearance', 'show_public_timeline', self.show_public_timeline,
                                   'Show public timeline','Show public timeline instead of tweets from friends'))

	self.add_option(StringOption('Appearance', 'public_title',
		self.public_title,
		'Public timeline label',
		'Label on the titlebar when showing tweets from public timeline'))

	self.add_option(StringOption('Appearance', 'friends_title',
		self.friends_title,
		"Followed tweets label",
		'Label on the titlebar when showing tweets of people followed'))

        self.add_option(IntOption('Appearance', 'update_interval', 
                                  self.update_interval, 'Update interval', 
                                  'The interval for refreshing status (in seconds)', min=1, max=9999))

        self.add_option(IntOption('Appearance', 'num_of_statuses', 
                                  self.num_of_statuses, 'Number of entries', 
                                  'Number of tweets to display',  min=0, max=100))

	self.add_option(FontOption('Appearance', 'item_font', 
			self.item_font, 'Font to use', 
			'Font to use to display tweets'))

        self.add_option(BoolOption('Appearance', 'entry_highlighting',
                                  self.entry_highlighting, 'Highlight active entry', 
                                  'Highlight entry under mouse cursor'))

        self.add_option(BoolOption('Appearance', 'show_tooltips',
                                  self.show_tooltips, 'Show tooltips', 
                                  'Do you really want to see tooltips on the widget?'))

        self.add_option(IntOption('Appearance', 'real_window_height',
                                  self.real_window_height, 'Window height', 
                                  'Height of the window',  min=100, max=9999))

        self.add_option(IntOption('Appearance', 'window_width',
                                  self.window_width, 'Window width', 
                                  'Width of the window',  min=150, max=9999))

        self.add_options_group('Account', 'You need to get an Access PIN to authorize Screenlet to access \nyour Twitter account. \n\nPlease empty the PIN field and press Apply to open your Twitter \npage for authorization. Log onto your account to authorize if you \nare not logged on automatically. After getting a PIN code, please \nreturn to this dialog, enter the PIN and press Apply again. If you \nwant to change the account to use just clear the PIN entry field \nand press Apply again.')

        self.add_option(StringOption('Account', 'access_pin',
			self.access_pin,
			"Access PIN",
			'Empty the field and click Apply to open URL to get Access PIN for the TwitterScreenlet'), realtime=False)

        self.add_option(StringOption('Account', 'access_key', 
			self.access_key, 'Access key', 
			'', hidden=True))

        self.add_option(StringOption('Account', 'access_secret', 
			self.access_secret, 'Access secret', 
			'', hidden=True))

        self.add_option(StringOption('Account', 'request_key', 
			self.request_key, 'request key', 
			'', hidden=True))

        self.add_option(StringOption('Account', 'request_secret', 
			self.request_secret, 'request secret', 
			'', hidden=True))

#        self.add_option(AccountOption('Account', 'account', 
#                                      self.account, 'Username/password', 
#                                      'Enter your username and password here...'))

        # scrolling is for tweets
        self.resize_on_scroll = False

        self.__notifier = screenlets.utils.Notifier(self)
	self._TwitterBackend__notifier = self.__notifier
#        self.update_buffer()
#        self.redraw_canvas()

#        gobject.idle_add(self.update)
#        self.__timeout = gobject.timeout_add(3000, self.on_draw, self)

    def __setattr__(self, name, value):
        # call Screenlet.__setattr__ in baseclass (ESSENTIAL!!!!)
        screenlets.Screenlet.__setattr__(self, name, value)

	if not self.initialized:
		return

        if name == "update_interval":

            if value > 0:
                self.__dict__['update_interval'] = value
                if self.__timeout:
                    gobject.source_remove(self.__timeout)
                self.__timeout = gobject.timeout_add(int(value) * 1000, self.update)
		print "timeout: " + str(int(value) * 1000)
            else:
                self.__dict__['update_interval'] = 1

        if name == 'access_secret':

		if self.show_public_timeline:
			self.__twitter = TwitterBackend(self, TwitterUpdateMethod.PUBLIC)
		else:
			self.__twitter = TwitterBackend(self, TwitterUpdateMethod.FRIENDS)

                self.__twitter.get_timeline_start()

	if name == 'show_tooltips':
		if self.__entry and self.__fixed:
			if self.show_tooltips:
				self.__entry.set_tooltip_text(self.entry_tooltip)
				self.__fixed.set_tooltip_text(self.status_tooltip)
			else:
				self.__entry.set_tooltip_text("")
				self.__fixed.set_tooltip_text("")

        if name == 'show_public_timeline':
            if self.__twitter:
                if self.show_public_timeline == False: # and self.access_key != '':
                    self.__twitter.set_update_method(TwitterUpdateMethod.FRIENDS)
                else:
                    self.__twitter.set_update_method(TwitterUpdateMethod.PUBLIC)
                
                self.__twitter.get_timeline_start()

        if name == 'access_pin':
            if self.__twitter and self.initialized:

#		print "PIN '" + self.access_pin + "'"

		if self.access_pin != "*******":

			if(len(self.access_pin) > 0):

				key = self.__twitter.get_access_key(self.access_pin, self.request_key, self.request_secret)
				if key is not None:
					self.access_key = key['oauth_token']
					self.access_secret = key['oauth_token_secret']
					self.__notifier.notify("Authentication successful!")

					self.access_pin = "*******"

				else:
					self.__notifier.notify("Problem with your access PIN. A renewal could help!")
	#				self.access_pin=""
			else:

				response = self.__twitter.open_access_url()
				url = response[0]
				if response[1] is not None and len(url) > 0:
					self.request_key = response[1]['oauth_token']
					self.request_secret = response[1]['oauth_token_secret']
					webbrowser.open_new_tab(url)
#					self.access_key = ""
#					self.access_secret = ""
				else:
					self.__notifier.notify("Problem connecting Twitter.com to update your access PIN!")

        if name == 'public_title':
            self.resize_and_redraw()

        if name == 'friends_title':
            self.resize_and_redraw()

        if name == 'num_of_statuses':
            self.resize_and_redraw()

        if name == 'real_window_height':
#            if value < 100:
#                self.__dict__['window_height'] = 100

            for status in self.__timeline.statuses:
                status.buffer = None
            self.resize_and_redraw()

        if name == 'window_width':
#            if value < 100:
#                self.__dict__['window_height'] = 100
            self.resize_and_redraw()

	if name == 'item_font':
	    print self.item_font
            self.resize_and_redraw()

        if name == 'entry_highlighting':
		self.update_buffer()
		self.redraw_canvas()

    def bare_windowsize(self):
		if not self.layout: return
		print "bare windowsize"
		self.window_x = self.layout.window.shadow_size
		self.window_y = 0

		#        self.window_width = self.layout.window.width
		self.window_height = self.real_window_height - self.header_height - self.footer_height;
		self.width = self.window_width + self.layout.window.shadow_size * 2
		self.height = self.header_height + self.footer_height + self.window_height + self.layout.window.shadow_size * 2
		self.modify_entry_pos()

    def resize_and_redraw(self):
        if not self.layout: return
        if not self.__twitter: return

        print "resize and redraw"

        for status in self.__timeline.statuses:
            status.buffer = None
            
        self.bare_windowsize()

        self.update_buffer()
        self.redraw_canvas()
        
    def get_border_width(self):
        if not self.layout: return 0
        ls = self.layout.status
        if ls.enable_border:
            return ls.border_width
        else:
            return 0

    def get_status_height(self, status):

        if not self.layout: return 0
        ls = self.layout.status

	status_text =  self.status_format % (ls.name_color.get_str(), 
		            status.GetUser().GetScreenName(),
		            ls.text_color.get_str(),
		            escape_for_pango_markup(status.GetText()))

	surface = cairo.ImageSurface (cairo.FORMAT_ARGB32, self.window_width-5-self.user_icon_size, 9999)
	cr = cairo.Context(surface)
	cr.clip()
	pcr = pangocairo.CairoContext(cr)

	play = pcr.create_layout()
        play.set_markup(status_text)
        play.set_single_paragraph_mode(False)
        play.set_wrap(pango.WRAP_WORD_CHAR)


        font_desc = pango.FontDescription()
	font_desc.set_family(self.item_font)

	temp_buf = str.split(self.item_font)
	real_size=temp_buf[len(temp_buf)-1]
        font_desc.set_size(int(real_size) * pango.SCALE)
	font_desc.set_weight(5)
	play.set_width((self.window_width-5-self.user_icon_size)*1024)
	play.set_alignment(pango.ALIGN_LEFT)
	play.set_ellipsize(pango.ELLIPSIZE_NONE)
	play.set_justify(False)

	play.set_font_description(font_desc)
	pcr.update_layout(play);

	t1, t2 = play.get_extents()

#	x_bearing, y_bearing, width, height, x_advance, y_advance = cr.text_extents(status_text)

#	print status_text + "\n" + status.GetUser().GetScreenName() + ": " + str(len(status.GetText())) + " / " + str(t2[3]/1024)
		
#	print status.GetUser().GetScreenName() + ": " + str(len(status.GetText())) + " / " + str(t1[0]) + "," +str(t1[1]) + "," +str(t1[2]) + "," +str(t1[3]) + " --- "+ str(t2[0]) + "," +str(t2[1]) + "," +str(t2[2]) + "," +str(t2[3])
#	print status.GetUser().GetScreenName() + ": " + str(len(status.GetText())) + " / " + str(height)

	self.status_height = max(self.user_icon_size+5, t2[3]/1024+3)

	return self.status_height
#        return self.status_height * self.num_of_statuses + self.get_border_width() * (self.num_of_statuses -1)


    def get_status_outer_height(self, status):
	return self.get_status_height(status) + self.get_border_width()
	

    def get_statuses_height(self):

        status_num = min(self.num_of_statuses, len(self.__timeline.statuses))

	adder = 0
	for index in range(status_num):
	    status = self.__timeline.statuses[index]
	    adder += self.get_status_outer_height(status)

#	print str(status_num) + " || " + str(adder)

	return adder - self.get_border_width() # last one does not have border



    def modify_entry_pos(self):

        print "mod entry pos"

        #move text entry
        if self.__entry:
            self.__entry.set_size_request(int((self.window_width - 20) * self.scale), -1)

        if self.__fixed:
            self.__fixed.move(self.__entry, int((10 + self.window_x) * self.scale), int((self.window_y + self.header_height + self.window_height + 5) * self.scale))
        self.window.show_all()        

    def update(self):
		if self.__twitter:
			self.__twitter.get_timeline_start()
			print "updating..."

		return True # timeout contintue

    def update_false(self):
		if self.__twitter:
			self.__twitter.get_timeline_start()
			print "false updating..."

		self.update_buffer()
		self.redraw_canvas()

		return False # timeout stop

    def on_after_set_atribute(self,name, value):
        """Called after setting screenlet atributes"""
        #print name + ' is going to change from ' + str(value)
        pass

    def on_before_set_atribute(self,name, value):
        """Called before setting screenlet atributes"""
        #print name + ' has changed to ' + str(value)
        pass


    def on_create_drag_icon (self):
        """Called when the screenlet's drag-icon is created. You can supply
        your own icon and mask by returning them as a 2-tuple."""
        return (None, None)

    def on_composite_changed(self):
        """Called when composite state has changed"""
        pass

    def on_drag_begin (self, drag_context):
        """Called when the Screenlet gets dragged."""
        pass

    def on_drag_enter (self, drag_context, x, y, timestamp):
        """Called when something gets dragged into the Screenlets area."""
        pass

    def on_drag_leave (self, drag_context, timestamp):
        """Called when something gets dragged out of the Screenlets area."""
        pass

    def on_drop (self, x, y, sel_data, timestamp):
        """Called when a selection is dropped on this Screenlet."""
        return False

    def on_focus (self, event):
        """Called when the Screenlet's window receives focus."""
        pass

    def on_hide (self):
        """Called when the Screenlet gets hidden."""
        pass

    def on_init (self):
		"""Called when the Screenlet's options have been applied and the 
		screenlet finished its initialization. If you want to have your
		Screenlet do things on startup you should use this handler."""
		print 'i just got started'

		self.width = self.width
		self.height = self.height

		# add  menu items from xml file
		self.add_default_menuitems(DefaultMenuItem.XML)
		# add menu item
		self.add_menuitem("refresh", "Refresh")
		# add default menu items
		self.add_default_menuitems()

		self.__entry = gtk.Entry(140)
		self.__entry.set_size_request(self.window_width,-1)
		self.__entry.set_has_frame(False)
		self.__fixed = gtk.Fixed()
		self.window.add(self.__fixed)
		self.__fixed.put(self.__entry, 0, 0)

#        self.__tooltips = gtk.Tooltip()

		if self.show_tooltips:
			self.__entry.set_tooltip_text(self.entry_tooltip)
			self.__fixed.set_tooltip_text(self.status_tooltip)

			self.bare_windowsize()

		#        self.modify_entry_pos()
		#        if not self.__twitter:
		#            self.__twitter = TwitterBackend(self, TwitterUpdateMethod.PUBLIC)

		#        self.update()

		if self.show_public_timeline:
			self.__twitter = TwitterBackend(self, TwitterUpdateMethod.PUBLIC)
		else:
			self.__twitter = TwitterBackend(self, TwitterUpdateMethod.FRIENDS)

		# because if it's available when starting it just obscures user
		self.access_pin=""

		self.initialized = True

		if not self.__timeout:
			self.__timeout = gobject.timeout_add(int(self.update_interval) * 1000, self.update)

		gobject.idle_add(self.update_false)

		#        self.update_buffer()
		#        self.redraw_canvas()

		self.resize_and_redraw()

#		print self.width, ", ", self.height

		#	if self.__timeout:
		#		gobject.source_remove(self.__timeout)
		#	self.__timeout = gobject.timeout_add(self.update_interval * 1000, self.update)
		#		print "timeout: " + str(int(value) * 1000)

		#        gobject.idle_add(self.update)
		#        self.__timeout = gobject.timeout_add(3100, self.update_buffer)
		#        self.__timeout = gobject.timeout_add(3200, self.redraw_canvas)
		#        self.__timeout = gobject.timeout_add(1000, self.update_false)

		#        self.window_height = self.header_height + self.footer_height + self.window_height + 2*self.layout.window.shadow_size

		#	print "win height: " + str(self.window_height)

		#	print self.access_key, self.access_secret, self.access_pin, self.request_key, self.request_secret


    def on_key_down(self, keycode, keyvalue, event):
        """Called when a keypress-event occured in Screenlet's window."""

	if self.__twitter:

		key = gtk.gdk.keyval_name(event.keyval)

		if key == "Return" and (event.state & gtk.gdk.SHIFT_MASK):

#			print "NUPP KÄIS"

			text = self.__entry.get_text()
			self.__entry.select_region(0, 140)
		    	self.__entry.set_sensitive(False)
		        self.__twitter.post_message_start(text)
		        self.__twitter.get_timeline_start()

    def on_load_theme (self):
        """Called when the theme is reloaded (after loading, before redraw)."""
        options_file = sys.path[0]+"/themes/"+self.theme_name+"/options.conf"
        if os.path.exists(options_file): 
            self.layout = ThemeParser(options_file)
        else:
            raise "Invalid Theme. No options.conf"

        self.resize_and_redraw()

    def on_menuitem_select (self, id):
        """Called when a menuitem is selected."""
        if id == "refresh":
            print "refresh"
            self.update()

    def get_status_index_under_pointer(self, x, y):
        try:
#	    print self.scale
	    y *= 1/self.scale
            if y > self.header_height and y < self.height - self.footer_height:
		
		y += self.statuses_offset
                # FIXME:

	        status_num = len(self.__timeline.statuses)

		adder = self.header_height
		for index in range(status_num):
#		    print "st " + str(index) + " of " + str(status_num)
		    status = self.__timeline.statuses[index]
		    inter = self.get_status_outer_height(status)
#		    print str(adder) + " <= " + str(y) + " < " + str(inter+adder)
		    if y>=adder and y<inter+adder:
#			print status.GetUser().GetScreenName()
			return index
		    adder += inter
		return -1

		

#                return self.__timeline.statuses[int((y - self.header_height + self.statuses_offset) /
#                                                    (self.status_height + self.get_border_width()) )]

            else:
                return None
        except:
            return None

    def get_status_under_pointer(self, x, y):
        try:
		index = get_status_index_under_pointer(self, x, y)
		if index:
			return self.__timeline.statuses[index]
		else:
			return None
        except:
            return None

    def on_mouse_down (self, event):
        """Called when a buttonpress-event occured in Screenlet's window. 
        Returning True causes the event to be not further propagated."""
        if event.button == 1:
            status = self.get_status_under_pointer(event.x, event.y)
            if status:
                return True
        return False

    def on_mouse_enter (self, event):
        """Called when the mouse enters the Screenlet's window."""
	index = self.get_status_index_under_pointer(event.x, event.y)
	if index < 0 or index > len(self.__timeline.statuses): return False
	status = self.__timeline.statuses[index]
	if status and self.highlight != index:
#		print status.GetUser().GetScreenName()
		self.highlight = index;
		self.update_buffer()
		self.redraw_canvas()

    def on_mouse_leave (self, event):
        """Called when the mouse leaves the Screenlet's window."""
#        self.hide_tooltip()
#        self.hover = False
#        self.__status_on_tooltip = None
        #print 'mouse leave'
	self.highlight = -1
	self.status = None
	self.update_buffer()
	self.redraw_canvas()

    def on_mouse_move(self, event):
        """Called when the mouse moves in the Screenlet's window."""

#        print 'mouse moves' + str(event.x) + " / "  + str(event.y)

	index = self.get_status_index_under_pointer(event.x, event.y)
	if index < 0 or index > len(self.__timeline.statuses): return False
	status = self.__timeline.statuses[index]
	if status and self.highlight != index:
#		print "UUS HAILAIT"
		self.highlight = index
		self.update_buffer()
		self.redraw_canvas()
	if 0:
		if status and status != self.__status_on_tooltip:
		    self.show_tooltip("%s\n%s" % (status.GetUser().GetScreenName(), 
				                  escape_for_pango_markup(status.GetText()))
				      ,self.x+self.mousex,self.y+self.mousey)
		    self.hover = True
		    self.__status_on_tooltip = status
		elif status == None:
		    self.hide_tooltip()
		    self.hover = False
		    self.__status_on_tooltip = None
            
    def on_mouse_up (self, event):
        """Called when a buttonrelease-event occured in Screenlet's window. 
        Returning True causes the event to be not further propagated."""
        if event.button == 1 and self.highlight >= 0:
            status = self.__timeline.statuses[self.highlight]
            if status:
                os.system('xdg-open http://twitter.com/' + status.GetUser().GetScreenName() + ' &')
                return True
        return False

    def on_quit (self):
        """Callback for handling destroy-event. Perform your cleanup here!"""
        # clear timeout
        if self.__timeout:
            gobject.source_remove(self.__timeout)

    def on_realize (self):
        """"Callback for handling the realize-event."""
        pass

    def on_scale (self):
        """Called when Screenlet.scale is changed."""
        self.resize_and_redraw()

    def on_scroll_up (self):
        """Called when mousewheel is scrolled up (button4)."""
        self.statuses_offset -= self.scroll_width
        if self.statuses_offset < 0 : self.statuses_offset = 0
        self.redraw_canvas()
#	print "offset: " + str(self.statuses_offset)
        return True

    def on_scroll_down (self):
        """Called when mousewheel is scrolled down (button5)."""
        self.statuses_offset += self.scroll_width
#	print "offset: " + str(self.statuses_offset) + " --- " + str(self.get_statuses_height() - self.window_height) + " ("  + str( self.buffer_height) + ")"
        if self.statuses_offset > self.get_statuses_height() - self.window_height:
		if self.get_statuses_height() - self.window_height > 0: 	
			self.statuses_offset = self.get_statuses_height() - self.window_height
		else:
			self.statuses_offset = 0
        self.redraw_canvas()
        return True
      
    def on_show (self):
        """Called when the Screenlet gets shown after being hidden."""
        pass

    def on_switch_widget_state (self, state):
        """Called when the Screenlet enters/leaves "Widget"-state."""
        pass

    def on_unfocus (self, event):
        """Called when the Screenlet's window loses focus."""
        pass

    def on_draw (self, ctx):
        """In here we load the theme"""
#        print "on draw"

        if not self.layout: return

        l = self.layout
        ctx.save()
        ctx.scale(self.scale , self.scale)
        ctx.translate(self.window_x, self.window_y)

        #draw shadow
        if l.window.shadowed:
            shadow_size = l.window.shadow_size
            self.draw_shadow(ctx, -self.window_x, -self.window_y, self.window_width, self.real_window_height ,shadow_size,l.window.shadow_color)

        # draw header
        ctx.save()
        self.round_rectangle(ctx, 0, 0, self.window_width, self.header_height, l.window.radius, l.window.radius, 0, 0)
        ctx.clip()
        linear = cairo.LinearGradient(0, 0, 0, self.header_height)
        linear.add_color_stop_rgba(0, *l.header.start_color.get())
        linear.add_color_stop_rgba(1.0,*l.header.end_color.get())
        ctx.set_source(linear)
        ctx.paint()
        ctx.restore()

#        if self.show_public_timeline == False and self.access_key != '': header_str = self.friends_title 
        if self.show_public_timeline == False: header_str = self.friends_title 
        else: header_str = self.public_title


	if l.header.hommage_to_twitter:
	        ctx.save()
        	self.draw_blurb(ctx, header_str, 10, 5, self.item_font, self.window_width,
                       allignment=pango.ALIGN_LEFT,
                       weight=pango.WEIGHT_BOLD,
                       ellipsize=pango.ELLIPSIZE_NONE, howlong=5)


        	ctx.restore()

        ctx.save()
        ctx.set_source_rgba(*l.header.title_color.get())
        self.draw_text(ctx, header_str, 10, 5, self.item_font, self.window_width,
                       allignment=pango.ALIGN_LEFT,
                       weight=pango.WEIGHT_BOLD,
                       ellipsize=pango.ELLIPSIZE_NONE)


        ctx.restore()

        # draw twitter logo
        #ctx.save()
        #ctx.translate(120,6)
        #ctx.scale(.4,.4)
        #self.theme.render(ctx, 'logo')
        #ctx.restore()

        # draw status buffer(refreshed by update_buffer())
        ctx.save()
        if self._buffer:
            ctx.translate(0,self.header_height)
            ctx.set_source_rgba(0,0,0,0)
            ctx.rectangle(0,0,self.window_width,self.window_height)
            ctx.clip()
            ctx.set_operator(cairo.OPERATOR_OVER)
            ctx.set_source_pixmap(self._buffer, 0, -self.statuses_offset)
            ctx.paint()
        ctx.restore()

        # draw footer
        ctx.save()
        ctx.translate(0, self.header_height + self.window_height)
        self.round_rectangle(ctx, 0, 0, self.window_width, self.footer_height, 0, 0, l.window.radius, l.window.radius)
        ctx.clip()
        linear = cairo.LinearGradient(0, 0, 0, self.footer_height)
        linear.add_color_stop_rgba(0.0, *l.footer.start_color.get())
        linear.add_color_stop_rgba(1.0, *l.footer.end_color.get())
        ctx.set_source(linear)
        ctx.paint()
        ctx.restore()

        ctx.restore()

    def draw_blurb (self, ctx, header_str, x, y, item_font, window_width, howlong,
                       allignment=pango.ALIGN_LEFT,
                       weight=pango.WEIGHT_BOLD,
                       ellipsize=pango.ELLIPSIZE_NONE):

#    def draw_text(self, ctx, text, x, y,  font, width, allignment=pango.ALIGN_LEFT,alignment=None,justify = False,weight = 0, ellipsize = pango.ELLIPSIZE_NONE, is_single_p=False):

		howlong = float(howlong)

		if not self.layout.status:
			return

		#        ls = self.layout.status

		o1 = o2 = o3 = 1

		#	o1, o2, o3, o4 = ls.odd_line_color.get()
		adder = float(0)
		for adder in range(int(howlong)):
			coef = (howlong-adder)/(howlong*1.5)
			ctx.set_source_rgba(1,1,1,coef)
			self.draw_text(ctx, header_str, x-adder, y-adder, self.item_font, self.window_width,
				   allignment=pango.ALIGN_LEFT,
				   weight=pango.WEIGHT_BOLD,
				   ellipsize=pango.ELLIPSIZE_NONE)
			self.draw_text(ctx, header_str, x+adder, y+adder, self.item_font, self.window_width,
				   allignment=pango.ALIGN_LEFT,
				   weight=pango.WEIGHT_BOLD,
				   ellipsize=pango.ELLIPSIZE_NONE)
			self.draw_text(ctx, header_str, x-adder, y+adder, self.item_font, self.window_width,
				   allignment=pango.ALIGN_LEFT,
				   weight=pango.WEIGHT_BOLD,
				   ellipsize=pango.ELLIPSIZE_NONE)
			self.draw_text(ctx, header_str, x+adder, y-adder, self.item_font, self.window_width,
				   allignment=pango.ALIGN_LEFT,
				   weight=pango.WEIGHT_BOLD,
				   ellipsize=pango.ELLIPSIZE_NONE)
			self.draw_text(ctx, header_str, x, y+adder, self.item_font, self.window_width,
				   allignment=pango.ALIGN_LEFT,
				   weight=pango.WEIGHT_BOLD,
				   ellipsize=pango.ELLIPSIZE_NONE)
			self.draw_text(ctx, header_str, x, y-adder, self.item_font, self.window_width,
				   allignment=pango.ALIGN_LEFT,
				   weight=pango.WEIGHT_BOLD,
				   ellipsize=pango.ELLIPSIZE_NONE)
			self.draw_text(ctx, header_str, x+adder, y, self.item_font, self.window_width,
				   allignment=pango.ALIGN_LEFT,
				   weight=pango.WEIGHT_BOLD,
				   ellipsize=pango.ELLIPSIZE_NONE)
			self.draw_text(ctx, header_str, x-adder, y, self.item_font, self.window_width,
				   allignment=pango.ALIGN_LEFT,
				   weight=pango.WEIGHT_BOLD,
				   ellipsize=pango.ELLIPSIZE_NONE)




    def on_draw_shape (self, ctx):
        self.on_draw(ctx)

    def on_get_timeline (self, timeline, result):
        """ call by TwitterBackend thread"""
        if TwitterResult.ERROR == result:
            self.__notifier.notify("Failed to get timeline")
            return

        print "got timeline"
        self.__timeline = timeline
        self.resize_and_redraw()

    def on_post_message (self, result):
        """ call by TwitterBackend thread"""
        if TwitterResult.ERROR == result:
		self.__notifier.notify("Failed to post the message!")
	else:
	        self.__entry.set_text("")

	self.__entry.set_sensitive(True)

    def update_buffer(self):
        if not self.window.window: return
        if not self.layout: return

#        print "update bufffer"

#        self.statuses_offset = 0

        status_num = max(self.num_of_statuses, len(self.__timeline.statuses))
#        self.buffer_height = status_num * self.status_height + (status_num -1) * self.get_border_width()

        self.buffer_height = status_num * 500

        self._buffer = gtk.gdk.Pixmap(self.window.window, 
                                    int(self.window_width), int(self.buffer_height), -1)

        ctx = self._buffer.cairo_create()
        self.clear_cairo_context(ctx)
        ctx.set_source_rgba(1,1,1,1)

#	print "offset_update_buf: " + str(self.statuses_offset)
#	ctx.set_source_pixmap(self._buffer, 0, -self.statuses_offset)

#        self.draw_status_bg(ctx, status_num)


# siin on asjad

#        status_num = max(self.num_of_statuses, len(self.__timeline.statuses))

#        status_num = len(self.__timeline.statuses)

        status_num = min(self.num_of_statuses, len(self.__timeline.statuses))


        ctx.save()
	index = 0
#	print "statuses to disp: " + str(status_num)
        for index in range(status_num):
#	    print "current: " + str(index)

            status = self.__timeline.statuses[index]
            self.draw_user_status(ctx, status, index)
            ctx.translate(0, self.get_status_height(status))
            if index < status_num-1: ctx.translate(0, self.get_border_width())
		# the last one doesn't have border down of it
	self.draw_status_outro(ctx, index+1)
	ctx.translate(0, self.window_height)
	ctx.translate(0, self.get_border_width())
        ctx.restore()





    def draw_status_outro (self, ctx, index):
        """ draw user status outro gradient"""

        if not self.window.window:
            return

        if not self.layout.status:
            return

        ls = self.layout.status

	# draw outro
	ctx.save()

#	pat = cairo.LinearGradient (0.0, 0.0, 0.0, 1.0)
#	pat.add_color_stop_rgba (1, 0.7, 0, 0, 0.5) # First stop, 50% opacity
#	pat.add_color_stop_rgba (0, 0.9, 0.7, 0.2, 1) # Last stop, 100% opacity



	o1, o2, o3, o4 = ls.odd_line_color.get()
	e1, e2, e3, e4 = ls.even_line_color.get()

	lg3 = cairo.LinearGradient(0.0, 0.0,  0.0, self.window_height)
	if  index % 2: # index 0 = line 1
		lg3.add_color_stop_rgba(0, o1, o2, o3, o4)         
	else:
		lg3.add_color_stop_rgba(0, e1, e2, e3, e4)         
#	lg3.add_color_stop_rgba(0.5, 1, 1, 0, 1) 
	lg3.add_color_stop_rgba(1, 1, 1, 1, 0) 

#	linear = cairo.LinearGradient(0, 0, 0, self.window_height)
#	o1, o2, o3, o4 = ls.odd_line_color.get()
#	e1, e2, e3, e4 = ls.even_line_color.get()

#	linear.add_color_stop_rgba(1, 0.7, 0, 0, 0.5)         
#	linear.add_color_stop_rgba(0, 0.9, 0.7, 0.2, 1)         

#	if  index % 2: # index 0 = line 1
#		linear.add_color_stop_rgba(0, o1, o2, o3, o4)         
#		linear.add_color_stop_rgba(1, e1, e2, e3, e4)         
#	else:
#		linear.add_color_stop_rgba(1, o1, o2, o3, o4)         
#		linear.add_color_stop_rgba(0, e1, e2, e3, e4)         

#	linear = cairo.LinearGradient(0, 0, self.window_width, self.window_height)          
#	ctx.set_source_rgba(*ls.odd_line_color.get())
#	ctx.set_source_rgba(0.8, 0.1, 0.3, 0.7)
	ctx.set_source(lg3)                     
	self.draw_rectangle(ctx,0,0,self.window_width,self.window_height)
#	ctx.fill()         

	ctx.translate(0, self.window_height)
	if ls.enable_border:
		ctx.save()
		ctx.set_source_rgba(*ls.border_color.get())
		self.draw_rectangle(ctx,0,0,self.window_width, self.get_border_width())
		ctx.restore()
		ctx.translate(0, self.get_border_width())

	ctx.restore()



    def draw_user_status (self, ctx, status, index):
        """ draw user status"""


        if not self.window.window:
            return

        if not self.layout.status:
            return

        ls = self.layout.status



#status background

	text_color = ls.text_color.get_str()
	name_color = ls.name_color.get_str()

	ctx.save()
#	print index % 2
	if self.entry_highlighting and index == self.highlight:

		if  index % 2: # index 0 = line 1
			ctx.set_source_rgba(*ls.even_line_hl_color.get())                              
			text_color = ls.even_line_hl_text_color.get_str()
		else:
			ctx.set_source_rgba(*ls.odd_line_hl_color.get())                              
			text_color = ls.even_line_hl_text_color.get_str()
	else:
		if  index % 2: # index 0 = line 1
			ctx.set_source_rgba(*ls.even_line_color.get())
		else:
			ctx.set_source_rgba(*ls.odd_line_color.get())

	self.draw_rectangle(ctx,0,0,self.window_width,self.get_status_height(status))

        status_num = min(self.num_of_statuses, len(self.__timeline.statuses))

	ctx.translate(0, self.get_status_height(status))
	if ls.enable_border and index < status_num - 1:
		ctx.save()
		ctx.set_source_rgba(*ls.border_color.get())
		self.draw_rectangle(ctx,0,0,self.window_width, self.get_border_width())
		ctx.restore()
		ctx.translate(0, self.get_border_width())


	ctx.restore()



        if status.buffer == None:

            status_text =  self.status_format % (name_color, 
                                            status.GetUser().GetScreenName(),
                                            text_color,
                                            escape_for_pango_markup(status.GetText()))

#            print len(status.GetText())
            

#            buffer = gtk.gdk.Pixmap(self.window.window, 
#                                    int(self.window_width), int(self.status_height), -1)

            buffer = gtk.gdk.Pixmap(self.window.window, 
                                    int(self.window_width),
				    self.get_status_height(status),
			            -1)

            text_ctx = buffer.cairo_create()
            self.clear_cairo_context(text_ctx)
            text_ctx.set_source_rgba(1,1,1,1)


            self.draw_text(text_ctx, status_text, 
                           self.user_icon_size + 4, 2, 
                           self.item_font, 
                           self.window_width-5-self.user_icon_size, 
                           allignment=pango.ALIGN_LEFT, 
                           weight=5,
                           ellipsize=pango.ELLIPSIZE_NONE)
            status.buffer = buffer


        ctx.save()
        #ctx.set_source_rgba(0,0,0,0)
        #ctx.rectangle(0,0,self.window_width, self.status_height)
        #ctx.clip()
        ctx.set_operator(cairo.OPERATOR_OVER)
        ctx.set_source_pixmap(status.buffer, 0, 0)
        ctx.paint()
        ctx.restore()

        self.draw_user_icon(ctx, 2, 2, self.user_icon_size, self.user_icon_size, 4.0, 1, self.__timeline.users[status.GetUser().GetId()])



    def draw_text(self, ctx, text, x, y,  font, width, allignment=pango.ALIGN_LEFT,alignment=None,justify = False,weight = 0, ellipsize = pango.ELLIPSIZE_NONE, is_single_p=False):
        """Draws text"""

        ctx.save()
        ctx.translate(x, y)
        if self.p_layout == None :
            self.p_layout = ctx.create_layout()
        else:
            ctx.update_layout(self.p_layout)
        if self.p_fdesc == None:self.p_fdesc = pango.FontDescription()
        else: pass
        self.p_fdesc.set_family(font)
	temp_buf = str.split(font)
	real_size=temp_buf[len(temp_buf)-1]
        self.p_fdesc.set_size(int(real_size) * pango.SCALE)
        self.p_fdesc.set_weight(weight)
        self.p_layout.set_font_description(self.p_fdesc)
        self.p_layout.set_width(width * pango.SCALE)
        self.p_layout.set_alignment(allignment)
        if alignment != None:self.p_layout.set_alignment(alignment)
        self.p_layout.set_justify(justify)
        self.p_layout.set_ellipsize(ellipsize)
        self.p_layout.set_markup(text)
        ###
        self.p_layout.set_single_paragraph_mode(False)
        self.p_layout.set_wrap(pango.WRAP_WORD_CHAR)
        ###

#	x1, y1, x2, y2 = ctx.clip_extents()

#	print str(y2-y1) 	

        ctx.show_layout(self.p_layout)
        ctx.restore()


    # from PidginScreenlet
    # Draw User Icon (Display Picture) 
    def draw_user_icon (self, ctx, x, y, w, h, rounding_radius, transparency, user):
        if user.iconPixbuf:
            ctx.save()
            ctx.translate(x, y)
            r = rounding_radius
            if r: self.round_rectangle(ctx,0,0,w,h,r,r,r,r)
            else: ctx.rectangle(0,0,w,h)
            ctx.clip()
            ctx.set_source_pixbuf(scaleGdkPixbuf(user.iconPixbuf,self.user_icon_size), 0, 0)
            ctx.paint_with_alpha(transparency)
            #ctx.paint()
            ctx.restore()

    # from PidginScreenlet
    # r1: top-left radius, r2: top-right radius, 
    # r3: bottom-left radius, r4: bottom-right radius
    def round_rectangle(self, ctx, x, y, width, height, r1, r2, r3, r4):
        ctx.move_to(x+r1, y)
        ctx.line_to(x+width-r2,y)
        # top right
        if r2 > 0:
                ctx.arc(x+width-r2, y+r2, r2, -PI/2.0, 0)
        ctx.line_to(x+width,y+height-r4)
        # bottom right
        if r4 > 0:
                ctx.arc(x+width-r4, y+height-r4, r4, 0, PI/2.0)
        ctx.line_to(x+r3, y+height)
        # bottom left
        if r3 > 0:
                ctx.arc(x+r3, y+height-r3, r3, PI/2.0, PI)
        ctx.line_to(x,y+r1)
        # top left
        if r1 > 0:
                ctx.arc(x+r1, y+r1, r1, PI, PI*1.5)


    def draw_status_bg(self, ctx, status_num):
        """ draw status background"""
        
        if not self.layout: return

        ls = self.layout.status
        ctx.save()
        for index in range(status_num):
            if  index % 2: # index 0 = line 1
                ctx.set_source_rgba(*ls.even_line_color.get())
            else:
                ctx.set_source_rgba(*ls.odd_line_color.get())
                
            self.draw_rectangle(ctx,0,0,self.window_width,self.get_status_height(self.__timeline.statuses[index]))

            ctx.translate(0, self.get_status_height(self.__timeline.statuses[index]))
            if ls.enable_border and index < status_num - 1:
                ctx.save()
                ctx.set_source_rgba(*ls.border_color.get())
                self.draw_rectangle(ctx,0,0,self.window_width, self.get_border_width())
                ctx.restore()
                ctx.translate(0, self.get_border_width())

        ctx.restore()

        
if __name__ == "__main__":
    # create new session
    import screenlets.session
    screenlets.session.create_session(TwitterScreenlet, threading=True)
